Skip to content

quant serve: portal rules and remote KV (7.4.0) - #298

Merged
stooit merged 32 commits into
mainfrom
feat/serve-phase3
Nov 4, 2026
Merged

stooit merged 32 commits into
mainfrom
feat/serve-phase3

Conversation

@stooit

@stooit stooit commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Adds two start-up options to quant serve that read from the portal. Both need QUANT_API_TOKEN and QUANT_BASE_URL in the environment. Nothing read from the portal is written to disk.

Stacked on #297 (7.3.0). Merge #297 first; this PR then shows only the 7.4.0 commits.

--pull-rules

  • Reads the project's rules (rules:read) and global headers (projects:read) once at start, and runs them in edge order with the rules of quant/edge-rules.json.
  • A local rule replaces its deployed copy (same namespace and id). Other portal rules keep their order.
  • New local rule actions: redirect, headers, custom response, basic auth, error page, proxy. Cookie conditions are checked.
  • Rules with country, IP, ASN, user agent or traffic source conditions, and bot challenge / serve-static rules, are skipped with a warning.
  • The start-up output shows the rule count and the global header count.

--kv-remote <store>

  • Copies one KV store (at most 10,000 keys) into memory at start. Local writes stay local for the session. Encrypted values stay masked. Ledger entries are not copied.
  • Finds the store by its quant/meta.json name, also when the portal list shows a display name.

Limits

  • One shared budget of 200 portal requests for the start-up, retries included. A 429 waits for Retry-After.

Tests

  • 736 unit tests, conformance suite, lint.
  • An end-to-end test runs the CLI against a local fake portal.
  • Tested on a real QuantGov project with --pull-rules --kv-remote together: rule order, global headers, KV reads and local writes, no writes to the portal.

stooit added 30 commits November 4, 2026 18:52
A 422 can say that the requested rule order cannot be kept (a retry does
not help), and a 409 can say that the change may already be live. Print
that message as one short line. The old texts stay as the fallback when
the response has no message.
…to the background

When the --run command exits 0 and its process group is still alive, print
one notice that it moved to the background instead of "stopped (exit code
0)". quant serve already stops the whole group on exit. When only the
--proxy URL still answers, say that quant serve cannot stop that dev
server. A non-zero exit keeps the old message. Windows has no process
group, which the README now says.
The value is stored as a function stores it with secret: true. A function
on quant serve reads it, and a list shows it masked.
quant serve and quant kv --local read optional org, project and meta from
quant/serve.json, so a project without quant.json needs no flags on every
call. A flag still wins, and quant/serve.json wins over quant.json. The
values are validated.
…nt org or project

The quant/serve.json value is used. quant serve prints the warning in the
start-up output, and quant kv --local prints it to stderr.
A yes/no question after the JSON value, default no.
…code

A string error without a message is printed above the old advice (retry
for 409, check URL and scopes for 422). A message still replaces the
advice. deployError moves its text into helpers (complexity 10 or less).
…e stops

stopRun aborts the poll, so it never keeps Node alive after a stop.
set prints the entry with the value [ENCRYPTED], the mask of a list. The
menu asks for a secret value with hidden input. --secret on get, list or
delete prints one notice that it is ignored.
The portal client calls an optional onRequest hook for each HTTP attempt,
so readStore counts 429 retries in requests and in maxRequests. A keys page
with has_more and no next_cursor now stops the read as truncated.
…place

A rules deploy creates or updates only the manifest rules of its own
namespace and never removes a rule. The merge now drops only a pulled
managed rule whose deploy namespace and id match a rule of
quant/edge-rules.json, and keeps every other pulled rule in its order.
…rors

- One request budget of 200 for the whole start-up, shared by the rules,
  headers and KV reads. The client checks it before each attempt, 429
  retries included, and refuses the attempt once it is spent. The KV
  read then stops as truncated (request limit).
- A 5xx or no answer from the project headers gives one warning and no
  portal global headers instead of a stop. The 403 warning names the
  headers read.
- static_error_page is on for any value that is not empty.
- readStore no longer takes a request count or returns one.
ruleLabel comes from rule-actions.js, listsStatus from rules.js, and
isObject from src/helper/is-object.js. No behaviour change.
The portal store list can send a display name in name (for example
"org/project: store"). Match the meta.json name on user_name first,
then on the project store id, then on name.
Add a docs note that the trailing-slash setting and the edge cache
settings are not pulled.
@stooit
stooit merged commit 28ea49a into main Nov 4, 2026
7 checks passed
@stooit
stooit deleted the feat/serve-phase3 branch November 4, 2026 21:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant